package com.jxmobi.util.ftp;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.stream.Stream;

/**
 *  the algorithm goes like this:
 *  1. list the content of the local directory
 *  2. For each item in the directory:
 *      * if the item is a file, then upload it to the server
 *      * if the item is a directory:
 *          * create the directory on the server
 *          * uploading the subdirectory by repeating step 1,2,3
 *  3. Return if the directory is empty or if the last item is processed
 *
 *  possible mail support: http://www.codejava.net/java-ee/javamail/send-e-mail-with-attachment-in-java
 *
 * @author fei <a href="mailto:xchen@jxmobi.com">Email the author</a>
 * @version 1.0 6/6/16
 */
public class FTPUtil {
    private static final Logger log = LoggerFactory.getLogger(FTPUtil.class);

    /**
     *
     * @param ftpClient
     * @param remoteDirPath path of the destination directory on the server
     * @param localParentDir path of the local directory being uploaded
     * @param remoteParentDir path of the parent directory of the current directory
     *                        on the server (used by recursive calls)
     * @throws IOException
     */
    public static void uploadDirectory(FTPClient ftpClient, String remoteDirPath, String localParentDir, String remoteParentDir) throws IOException {
        // code to upload a whole directory

        log.debug(" Listing directory: " + localParentDir);

        File localDir = new File(localParentDir);
        File[] subFiles = localDir.listFiles();

        if (subFiles != null && subFiles.length > 0) {
            for (File item :
                    subFiles) {
                String remoteFilePath = remoteDirPath + File.separator + remoteParentDir
                        + File.separator + item.getName();

                if (remoteParentDir.equals("")) {
                    remoteFilePath = remoteDirPath + File.separator + item.getName();
                }

                if (item.isFile()) {
                    // upload the file
                    String localFilePath = item.getAbsolutePath();
                    log.debug("about to upload the file: " + localFilePath);

                    boolean uploaded = uploadSingleFile(ftpClient, localFilePath, remoteFilePath);

                    if (uploaded) {
                        log.debug(" successfully upload a file :[" + localFilePath + "] to the remote ftp server");
                    } else {
                        log.error(" failed upload a file :[" + localFilePath + "] to the remote ftp server");
                    }
                }

                else {
                    boolean created = ftpClient.makeDirectory(remoteFilePath);
                    if (created) {
                        log.debug("CREATED the directory: "
                                + remoteFilePath);
                    } else {
                        log.error("COULD NOT create the directory: "
                                + remoteFilePath);
                    }

                    // upload the sub directory
                    String parent = remoteParentDir + File.separator + item.getName();
                    if (remoteParentDir.equals("")) {
                        parent = item.getName();
                    }

                    localParentDir = item.getAbsolutePath();
                    uploadDirectory(ftpClient, remoteDirPath, localParentDir,
                            parent);
                }

            }
        }

    }

    public static boolean uploadSingleFile(FTPClient ftpClient, String localFilePath, String remoteFilePath) throws IOException {
        // code to upload a single file to the server ..
        File localFile = new File(localFilePath);

        InputStream inputStream = new FileInputStream(localFile);
        try {
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            return ftpClient.storeFile(remoteFilePath, inputStream);
        } finally {
            inputStream.close();
        }
    }

    /**
     * Upload structure of a directory (without uploading files) to a FTP
     * server.
     *
     * @param ftpClient
     *            an instance of org.apache.commons.net.ftp.FTPClient class.
     * @param remoteDirPath
     *            Path of the destination directory on the server.
     * @param localParentDir
     *            Path of the local directory being uploaded.
     * @param remoteParentDir
     *            Path of the parent directory of the current directory on the
     *            server (used by recursive calls).
     * @throws IOException
     *             if any network or IO error occurred.
     */
    public static void uploadDirStructure(FTPClient ftpClient,
                                          String remoteDirPath, String localParentDir, String remoteParentDir)
            throws IOException {

        File localDir = new File(localParentDir);
        File[] subFiles = localDir.listFiles();
        if (subFiles != null && subFiles.length > 0) {
            for (File item : subFiles) {
                if (item.isDirectory()) {
                    String remoteFilePath = remoteDirPath + File.separator
                            + remoteParentDir + File.separator + item.getName();
                    if (remoteParentDir.equals("")) {
                        remoteFilePath = remoteDirPath + File.separator + item.getName();
                    }

                    // create directory on the server
                    boolean created = ftpClient.makeDirectory(remoteFilePath);
                    if (created) {
                        log.debug("CREATED the directory: "
                                + remoteFilePath);
                    } else {
                        log.error("COULD NOT create the directory: "
                                + remoteFilePath);
                    }

                    // upload the sub directory
                    String parent = remoteParentDir + File.separator + item.getName();
                    if (remoteParentDir.equals("")) {
                        parent = item.getName();
                    }

                    localParentDir = item.getAbsolutePath();
                    uploadDirStructure(ftpClient, remoteDirPath, localParentDir,
                            parent);
                }
            }
        }
    }
}
